From af3b1a731e1fc8f2b695cac464ad24a9a2e0a6e3 Mon Sep 17 00:00:00 2001 From: Ralf Horstmann Date: Tue, 21 Jan 2020 23:10:34 +0100 Subject: [PATCH] Convert ggv_bin format to sub-class of Format (#462) * Convert ggv_bin format to sub-class of Format * Add ggv_bin helpers as class member functions * Style improvements in ggv_bin --- CMakeLists.txt | 1 + GPSBabel.pro | 1 + Makefile.in | 6 +- ggv_bin.cc | 208 ++++++++++++++++++++++++------------------------- ggv_bin.h | 79 +++++++++++++++++++ vecs.h | 4 +- 6 files changed, 189 insertions(+), 110 deletions(-) create mode 100644 ggv_bin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 673e38abf..1a34bbaaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,7 @@ set(HEADERS gbser.h gbser_private.h gbversion.h + ggv_bin.h gpx.h grtcirc.h heightgrid.h diff --git a/GPSBabel.pro b/GPSBabel.pro index 13b2cf416..89ed1eb3d 100644 --- a/GPSBabel.pro +++ b/GPSBabel.pro @@ -111,6 +111,7 @@ HEADERS = \ gbser.h \ gbser_private.h \ gbversion.h \ + ggv_bin.h \ gpx.h \ grtcirc.h \ heightgrid.h \ diff --git a/Makefile.in b/Makefile.in index aa1ba71f1..90e2fd249 100644 --- a/Makefile.in +++ b/Makefile.in @@ -581,7 +581,8 @@ geojson.o: geojson.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h \ inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \ src/core/file.h ggv_bin.o: ggv_bin.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h \ - inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h + inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \ + ggv_bin.h format.h ggv_log.o: ggv_log.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h \ inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \ grtcirc.h @@ -1008,7 +1009,8 @@ vcf.o: vcf.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h inifile.h \ vecs.o: vecs.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h inifile.h \ gbfile.h session.h src/core/datetime.h src/core/optional.h vecs.h \ format.h gpx.h src/core/file.h src/core/xmlstreamwriter.h \ - src/core/xmltag.h legacyformat.h gbversion.h src/core/logging.h xcsv.h + src/core/xmltag.h legacyformat.h gbversion.h src/core/logging.h xcsv.h \ + ggv_bin.h vidaone.o: vidaone.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h \ inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h vitosmt.o: vitosmt.cc defs.h config.h zlib/zlib.h zlib/zconf.h cet.h \ diff --git a/ggv_bin.cc b/ggv_bin.cc index bba7a3628..8d244128a 100644 --- a/ggv_bin.cc +++ b/ggv_bin.cc @@ -2,8 +2,8 @@ Handle Geogrid-Viewer binary overlay file format (.ovl) - Copyright (C) 2016 Ralf Horstmann - Copyright (C) 2016 Robert Lipe, robertlipe+source@gpsbabel.org + Copyright (C) 2016-2020 Ralf Horstmann + Copyright (C) 2016-2020 Robert Lipe, robertlipe+source@gpsbabel.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,92 +21,101 @@ */ -#include "defs.h" #include #include #include #include #include -#define MYNAME "ggv_bin" +#include "ggv_bin.h" -static QString read_fname; +#define MYNAME "ggv_bin" /*************************************************************************** * local helper functions * ***************************************************************************/ -static void -ggv_bin_read_bytes(QDataStream& stream, QByteArray& buf, int len, const char* descr = nullptr) +void +GgvBinFormat::ggv_bin_read_bytes(QDataStream& stream, QByteArray& buf, int len, const char* descr) { - if (len < 0) + if (len < 0) { fatal(MYNAME ": Read error, negative len (%s)\n", descr ? descr : ""); + } buf.resize(len); - if (stream.readRawData(buf.data(), len) != len || stream.status() != QDataStream::Ok) + if (stream.readRawData(buf.data(), len) != len || stream.status() != QDataStream::Ok) { fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); + } } -static quint16 -ggv_bin_read16(QDataStream& stream, const char* descr = nullptr) +quint16 +GgvBinFormat::ggv_bin_read16(QDataStream& stream, const char* descr) { quint16 res; stream >> res; - if (stream.status() != QDataStream::Ok) + if (stream.status() != QDataStream::Ok) { fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); - if (global_opts.debug_level > 1) + } + if (global_opts.debug_level > 1) { qDebug("ovl: %-15s %5u (0x%04x)", descr, res, res); + } return res; } -static quint32 -ggv_bin_read32(QDataStream& stream, const char* descr = nullptr) +quint32 +GgvBinFormat::ggv_bin_read32(QDataStream& stream, const char* descr) { quint32 res; stream >> res; - if (stream.status() != QDataStream::Ok) + if (stream.status() != QDataStream::Ok) { fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); + } if (global_opts.debug_level > 1) { - if ((res & 0xFFFF0000) == 0) + if ((res & 0xFFFF0000) == 0) { qDebug("ovl: %-15s %5u (0x%08x)", descr, res, res); - else + } else { qDebug("ovl: %-15s (0x%08x)", descr, res); + } } return res; } -static void -ggv_bin_read_text16(QDataStream& stream, QByteArray& buf, const char* descr = nullptr) +void +GgvBinFormat::ggv_bin_read_text16(QDataStream& stream, QByteArray& buf, const char* descr) { quint16 len = ggv_bin_read16(stream, descr); ggv_bin_read_bytes(stream, buf, len, descr); buf[len] = 0; - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug() << "ovl: text =" << QString::fromLatin1(buf.constData()).simplified(); + } } -static void -ggv_bin_read_text32(QDataStream& stream, QByteArray& buf, const char* descr = nullptr) +void +GgvBinFormat::ggv_bin_read_text32(QDataStream& stream, QByteArray& buf, const char* descr) { quint32 len = ggv_bin_read32(stream, descr); // The following check prevents passing an unsigned int with a // value greater than INT32_MAX to a signed int parameter in // ggv_bin_read_bytes later on. If this happens, the file is // almost certainly corrupted. - if (len > INT32_MAX) + if (len > INT32_MAX) { fatal(MYNAME ": Read error, max len exceeded (%s)\n", descr ? descr : ""); + } ggv_bin_read_bytes(stream, buf, len, descr); buf[len] = 0; - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug() << "ovl: text =" << QString::fromLatin1(buf.constData()).simplified(); + } } -static double -ggv_bin_read_double(QDataStream& stream, const char* descr = nullptr) +double +GgvBinFormat::ggv_bin_read_double(QDataStream& stream, const char* descr) { double res; stream >> res; - if (stream.status() != QDataStream::Ok) + if (stream.status() != QDataStream::Ok) { fatal(MYNAME ": Read error (%s)\n", descr ? descr : ""); + } return res; } @@ -114,8 +123,8 @@ ggv_bin_read_double(QDataStream& stream, const char* descr = nullptr) * OVL Version 2.0 * ***************************************************************************/ -static void -ggv_bin_read_v2(QDataStream& stream) +void +GgvBinFormat::ggv_bin_read_v2(QDataStream& stream) { QByteArray buf; QString track_name; @@ -131,15 +140,17 @@ ggv_bin_read_v2(QDataStream& stream) ggv_bin_read_bytes(stream, buf, header_len, "map name"); buf.remove(0,4); buf.append('\0'); - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug() << "ovl: name =" << buf.constData(); + } } while (!stream.atEnd()) { track_name.clear(); - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("------------------------------------ 0x%llx", stream.device()->pos()); + } auto entry_pos = stream.device()->pos(); quint16 entry_type = ggv_bin_read16(stream, "entry type"); @@ -171,7 +182,7 @@ ggv_bin_read_v2(QDataStream& stream) waypt_add(wpt); break; case 0x03: - // line + // line case 0x04: // area ggv_bin_read16(stream, "line color"); @@ -180,8 +191,9 @@ ggv_bin_read_v2(QDataStream& stream) line_points = ggv_bin_read16(stream, "line points"); ggv_bin_track = route_head_alloc(); track_add_head(ggv_bin_track); - if (! track_name.isEmpty()) + if (! track_name.isEmpty()) { ggv_bin_track->rte_name = track_name; + } for (int i = 1; i <= line_points; i++) { lon = ggv_bin_read_double(stream, "line lon"); @@ -193,9 +205,9 @@ ggv_bin_read_v2(QDataStream& stream) } break; case 0x05: - // rectangle + // rectangle case 0x06: - // circle + // circle case 0x07: // triangle ggv_bin_read16(stream, "geom color"); @@ -226,8 +238,8 @@ ggv_bin_read_v2(QDataStream& stream) * OVL Version 3.0 and 4.0 * ***************************************************************************/ -static void -ggv_bin_read_v34_header(QDataStream& stream, quint32& number_labels, quint32 &number_records) +void +GgvBinFormat::ggv_bin_read_v34_header(QDataStream& stream, quint32& number_labels, quint32& number_records) { QByteArray buf; @@ -246,18 +258,20 @@ ggv_bin_read_v34_header(QDataStream& stream, quint32& number_labels, quint32 &nu ggv_bin_read_bytes(stream, buf, header_len, "map name"); buf.remove(0,4); buf.append('\0'); - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug() << "ovl: name =" << buf.constData(); + } } } -static void -ggv_bin_read_v34_label(QDataStream& stream) +void +GgvBinFormat::ggv_bin_read_v34_label(QDataStream& stream) { QByteArray buf; - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("------------------------------------ 0x%llx", stream.device()->pos()); + } ggv_bin_read_bytes(stream, buf, 0x08, "label header"); ggv_bin_read_bytes(stream, buf, 0x14, "label number"); ggv_bin_read_text16(stream, buf, "label text"); @@ -265,8 +279,8 @@ ggv_bin_read_v34_label(QDataStream& stream) ggv_bin_read16(stream, "label flag2"); } -static QString -ggv_bin_read_v34_common(QDataStream& stream) +QString +GgvBinFormat::ggv_bin_read_v34_common(QDataStream& stream) { QByteArray buf; @@ -293,18 +307,19 @@ ggv_bin_read_v34_common(QDataStream& stream) return res; } -static void -ggv_bin_read_v34_record(QDataStream& stream) +void +GgvBinFormat::ggv_bin_read_v34_record(QDataStream& stream) { QByteArray buf; - Waypoint *wpt; + Waypoint* wpt; route_head* ggv_bin_track; quint32 bmp_len; quint16 line_points; double lon, lat; - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("------------------------------------ 0x%llx", stream.device()->pos()); + } quint16 entry_type = ggv_bin_read16(stream, "entry type"); QString label = ggv_bin_read_v34_common(stream); @@ -332,14 +347,15 @@ ggv_bin_read_v34_record(QDataStream& stream) break; case 0x03: case 0x04: - // area + // area case 0x17: // line ggv_bin_track = route_head_alloc(); track_add_head(ggv_bin_track); - - if (! label.isEmpty()) + + if (! label.isEmpty()) { ggv_bin_track->rte_name = label; + } ggv_bin_read16(stream, "line prop1"); ggv_bin_read32(stream, "line prop2"); @@ -397,8 +413,9 @@ ggv_bin_read_v34_record(QDataStream& stream) // value greater than INT32_MAX to a signed int parameter in // ggv_bin_read_bytes later on. If this happens, the file is // almost certainly corrupted. - if (bmp_len > INT32_MAX) + if (bmp_len > INT32_MAX) { fatal(MYNAME ": Read error, max bmp_len exceeded\n"); + } ggv_bin_read16(stream, "bmp prop"); ggv_bin_read_bytes(stream, buf, bmp_len, "bmp data"); break; @@ -407,8 +424,8 @@ ggv_bin_read_v34_record(QDataStream& stream) } } -static void -ggv_bin_read_v34(QDataStream& stream) +void +GgvBinFormat::ggv_bin_read_v34(QDataStream& stream) { QByteArray buf; quint32 label_count; @@ -418,31 +435,37 @@ ggv_bin_read_v34(QDataStream& stream) ggv_bin_read_v34_header(stream, label_count, record_count); if (label_count && !stream.atEnd()) { - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("-----labels------------------------- 0x%llx", stream.device()->pos()); - for (unsigned int i = 0; i < label_count; i++) + } + for (unsigned int i = 0; i < label_count; i++) { ggv_bin_read_v34_label(stream); + } } if (record_count && !stream.atEnd()) { - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("-----records------------------------ 0x%llx", stream.device()->pos()); - for (unsigned int i = 0; i < record_count; i++) + } + for (unsigned int i = 0; i < record_count; i++) { ggv_bin_read_v34_record(stream); + } } if (!stream.atEnd()) { - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug("------------------------------------ 0x%llx", stream.device()->pos()); + } // we just skip over the next magic bytes without checking they // contain the correct string. This is consistent with what I // believe GGV does ggv_bin_read_bytes(stream, buf, 23, "magicbytes"); - if (global_opts.debug_level > 1) + if (global_opts.debug_level > 1) { qDebug() << "ovl: header = " << buf.constData(); + } } } - + if (global_opts.debug_level > 1) { qDebug("fpos: 0x%llx", stream.device()->pos()); qDebug("size: 0x%llx", stream.device()->size()); @@ -450,14 +473,22 @@ ggv_bin_read_v34(QDataStream& stream) } /*************************************************************************** - * global callbacks called by gpsbabel main process * + * entry points called by gpsbabel main process * ***************************************************************************/ -static void -ggv_bin_read_file(QDataStream& stream) +void +GgvBinFormat::read() { - QByteArray buf; + QFile file(read_fname); + if (!file.open(QIODevice::ReadOnly)) { + fatal(MYNAME ": Error opening file %s\n", qPrintable(read_fname)); + } + QDataStream stream(&file); + stream.setFloatingPointPrecision(QDataStream::DoublePrecision); + stream.setByteOrder(QDataStream::LittleEndian); + + QByteArray buf; ggv_bin_read_bytes(stream, buf, 0x17, "magic"); buf[23] = 0; if (global_opts.debug_level > 1) { @@ -473,54 +504,19 @@ ggv_bin_read_file(QDataStream& stream) } else { fatal(MYNAME ": Unsupported file format\n"); } + + file.close(); } -static void -ggv_bin_read_init(const QString& fname) +void +GgvBinFormat::rd_init(const QString& fname) { read_fname = fname; } -static void -ggv_bin_read_deinit() +void +GgvBinFormat::rd_deinit() { read_fname.clear(); } -static void -ggv_bin_read() -{ - QFile file(read_fname); - - if (!file.open(QIODevice::ReadOnly)) { - fatal(MYNAME ": Error opening file %s\n", qPrintable(read_fname)); - } - - QDataStream stream(&file); - stream.setFloatingPointPrecision(QDataStream::DoublePrecision); - stream.setByteOrder(QDataStream::LittleEndian); - - ggv_bin_read_file(stream); - file.close(); -} - -ff_vecs_t ggv_bin_vecs = { - ff_type_file, - { - ff_cap_none, // waypoints - ff_cap_read, // tracks - ff_cap_none // routes - }, - ggv_bin_read_init, // rd_init - nullptr, // wr_init - ggv_bin_read_deinit, // rd_deinit - nullptr, // wr_deinit - ggv_bin_read, // read - nullptr, // write - nullptr, // exit - nullptr, //args - CET_CHARSET_ASCII, 0 //encode,fixed_encode - //NULL //name dynamic/internal? - , NULL_POS_OPS, - nullptr -}; diff --git a/ggv_bin.h b/ggv_bin.h new file mode 100644 index 000000000..61384092a --- /dev/null +++ b/ggv_bin.h @@ -0,0 +1,79 @@ +/* + + Handle Geogrid-Viewer binary overlay file format (.ovl) + + Copyright (C) 2016-2020 Ralf Horstmann + Copyright (C) 2016-2020 Robert Lipe, robertlipe+source@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#ifndef GGV_BIN_H_INCLUDED_ +#define GGV_BIN_H_INCLUDED_ + +#include "defs.h" +#include "format.h" + + +class GgvBinFormat : public Format +{ +public: + ff_type get_type() const override + { + return ff_type_file; + } + + QVector get_cap() const override + { + return { + ff_cap_none, // waypoints + ff_cap_read, // tracks + ff_cap_none // routes + }; + } + + QString get_encode() const override + { + return CET_CHARSET_ASCII; + } + + int get_fixed_encode() const override + { + return 0; + } + + void rd_init(const QString& fname) override; + void read() override; + void rd_deinit() override; + +private: + static void ggv_bin_read_bytes(QDataStream& stream, QByteArray& buf, int len, const char* descr = nullptr); + static quint16 ggv_bin_read16(QDataStream& stream, const char* descr = nullptr); + static quint32 ggv_bin_read32(QDataStream& stream, const char* descr = nullptr); + static void ggv_bin_read_text16(QDataStream& stream, QByteArray& buf, const char* descr = nullptr); + static void ggv_bin_read_text32(QDataStream& stream, QByteArray& buf, const char* descr = nullptr); + static double ggv_bin_read_double(QDataStream& stream, const char* descr = nullptr); + static void ggv_bin_read_v2(QDataStream& stream); + static void ggv_bin_read_v34_header(QDataStream& stream, quint32& number_labels, quint32& number_records); + static void ggv_bin_read_v34_label(QDataStream& stream); + static QString ggv_bin_read_v34_common(QDataStream& stream); + static void ggv_bin_read_v34_record(QDataStream& stream); + static void ggv_bin_read_v34(QDataStream& stream); + + QString read_fname; + +}; + +#endif diff --git a/vecs.h b/vecs.h index 8369376d5..6bb20cd57 100644 --- a/vecs.h +++ b/vecs.h @@ -28,6 +28,7 @@ #include "defs.h" #include "format.h" +#include "ggv_bin.h" #include "gpx.h" #include "legacyformat.h" @@ -174,7 +175,6 @@ extern ff_vecs_t mapfactor_vecs; extern ff_vecs_t energympro_vecs; extern ff_vecs_t mynav_vecs; extern ff_vecs_t geojson_vecs; -extern ff_vecs_t ggv_bin_vecs; extern ff_vecs_t globalsat_sport_vecs; #endif // MAXIMAL_ENABLED @@ -380,7 +380,7 @@ private: LegacyFormat energympro_fmt {energympro_vecs}; LegacyFormat mynav_fmt {mynav_vecs}; LegacyFormat geojson_fmt {geojson_vecs}; - LegacyFormat ggv_bin_fmt {ggv_bin_vecs}; + GgvBinFormat ggv_bin_fmt; LegacyFormat globalsat_sport_fmt {globalsat_sport_vecs}; #endif // MAXIMAL_ENABLED -- 2.30.2